package com.xsf.jieyou.business.service;

import com.google.common.collect.Maps;
import com.xsf.jieyou.business.BusinessException;
import com.xsf.jieyou.business.common.dto.ResponseResult;
import com.xsf.jieyou.business.common.dto.ResponseStatus;
import com.xsf.jieyou.business.dto.LoginParam;
import com.xsf.jieyou.commons.utils.MapperUtils;
import com.xsf.jieyou.commons.utils.OkHttpClientUtil;
import okhttp3.ResponseBody;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;

/**
 * 登录 业务层 , 主要是解决[账号密码/手机验证码/人脸识别/二维码/...]登录的oAuth2安全认证功能
 *
 * @author xsfno1
 * @version v1.0.0
 * @date 2020/3/11 4:58
 * @see com.xsf.jieyou.business.service
 **/
@Service
public class LoginServiceImpl {
    @Value("${oauth2.url}")
    private String oauth2Url;
    @Value("${oauth2.grant_type}")
    private String oauth2GrantType;
    @Value("${oauth2.client_id}")
    private String oauth2ClientId;
    @Value("${oauth2.client_secret}")
    private String oauth2ClientSecret;

    @Resource(name = "userDetailsServiceBean")
    private UserDetailsService userDetailsService;
    @Resource
    private BCryptPasswordEncoder passwordEncoder;


    /**
     * 用户登录
     * 对于无密码登录方式,通过设置默认密码完成登录
     *
     * @param loginParam {@link LoginParam} 登录数据传输对象
     * @return {@link ResponseResult}
     */
    public ResponseResult<?> login(LoginParam loginParam) {
        // 1、帐号密码验证
        UserDetails userDetails = this.userDetailsService.loadUserByUsername(loginParam.getUsername());

        // 密码错误，用户不存在则已在userDetailsService中抛出自定义异常
        if (!passwordEncoder.matches(loginParam.getPassword(), userDetails.getPassword())) {
            throw new BusinessException(ResponseStatus.ADMIN_PASSWORD);
        }
        // 2、申请令牌token
        String token = this.getToken(loginParam);

        // 2.1、令牌申请成功，失败(token==null)则已在userDetailsService中抛出自定义异常
        Map<String, Object> data = Maps.newHashMap();
        data.put("token", token);

        return new ResponseResult<>(ResponseStatus.SUCCESS, data);
    }

    /**
     * 通过 okHttp3 向 oAuth2 认证服务器 申请令牌token
     *
     * @param loginParam {@link LoginParam}
     * @return token令牌
     */
    private String getToken(LoginParam loginParam) {
        Map<String, String> bodyParams = Maps.newHashMap();
        bodyParams.put("username", loginParam.getUsername());
        bodyParams.put("password", loginParam.getPassword());
        bodyParams.put("grant_type", this.oauth2GrantType);
        bodyParams.put("client_id", this.oauth2ClientId);
        bodyParams.put("client_secret", this.oauth2ClientSecret);
        try {
            ResponseBody responseBody = OkHttpClientUtil.getInstance().postData(this.oauth2Url, bodyParams).body();
            if (responseBody != null) {
                String jsonStr = responseBody.string();
                Map<String, Object> map = MapperUtils.json2map(jsonStr);
                return map.get("access_token").toString();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        throw new BusinessException(ResponseStatus.GET_TOKEN_FAIL);
    }

}